#include "stdafx.h"
#include "EntityManager.h"
#include "Entity.h"

#include "EntityEvent.h"
#include "GameEngine.h"

using namespace std;

namespace ZeEngine
{
    EntityManager::EntityManager(GameEngine& gameEngine) : m_gameEngine(gameEngine)
	{
        m_allEntities.resize(100);
	}

	EntityManager::~EntityManager()
	{
		m_addEntities.clear();
		m_removeEntities.clear();
        m_allEntities.clear();
	}

	EntityDataStore& EntityManager::GetEntityDataStore(const std::string& group)
	{
		auto it = m_entityDataStore.find(group);

		if (it != m_entityDataStore.end())
		{
			return it->second;
		}

        m_entityDataStore.insert(pair<string, EntityDataStore>(group, EntityDataStore()));
		
		return m_entityDataStore[group];
	}

	Entity* EntityManager::CreateAndAddEntity(const std::string& name, const std::string& group)
	{       
        //Create new group if we cant find it
		auto it = m_entityDataStore.find(group);
		if (it == m_entityDataStore.end())
		{
            m_entityDataStore.insert(pair<string, EntityDataStore>(group, EntityDataStore()));
		}

		Entity* pEntity = m_entityDataStore[group].GetNewEntity(name);

		if (pEntity)
		{
			auto it = m_addEntities.find(group);
			if (it == m_addEntities.end())
			{
				m_addEntities.insert(pair<string, vector<Entity*>>(group, vector<Entity*>()));
			}

			m_addEntities[group].push_back(pEntity);
		}

		return pEntity;
	}

	void EntityManager::RemoveEntity(Entity* pEntity, const std::string& group)
	{
		if (pEntity)
        {
			auto it = m_removeEntities.find(group);
			if (it == m_removeEntities.end())
			{
				m_removeEntities.insert(pair<string, vector<Entity*>>(group, vector<Entity*>()));
			}

			m_removeEntities[group].push_back(pEntity);
		}
	}

	void EntityManager::Clear()
	{
		for (auto& store : m_entityDataStore)
		{
            for (auto& entity : store.second)
			{
                RemoveEntity(entity, store.first);
			}
		}
	}

	void EntityManager::PreUpdate()
	{
		//Add all new objects
		for each (auto entities in m_addEntities)
		{
			if (m_entityDataStore.find(entities.first) != m_entityDataStore.end())
			{
				for each (auto entity in entities.second)
				{
					m_entityDataStore[entities.first].Insert(entity);

                    while(m_allEntities.size() <= entity->GetID())
                    {
                        m_allEntities.resize(m_allEntities.size() * 2);
                        LOG_INFORMATION("Doubling entity Vector");
                    }
                    m_allEntities[entity->GetID()] = entity;

                    m_gameEngine.AddEvent(make_unique<EntityEvent>(*entity));
				}
			}
			else
			{
				assert(false && "Should not happen");
			}
		}

		m_addEntities.clear();
	}

	void EntityManager::PostUpdate()
	{
        for (auto& store : m_entityDataStore)
        {
            for (auto pEntity : store.second)
            {
                if (pEntity && pEntity->m_fRemove)
                {
                    RemoveEntity(pEntity, store.first);
                    m_allEntities[pEntity->GetID()] = nullptr;
                }
            }
        }

		//Remove all old objects  
		for each (auto entities in m_removeEntities)
		{
			if (m_entityDataStore.find(entities.first) != m_entityDataStore.end())
			{
				for each (auto entity in entities.second)
				{
					m_entityDataStore[entities.first].Remove(entity);
                    m_allEntities[entity->GetID()] = nullptr;
				}
			}
			else
			{
				LOG_ERROR("Could not find data store group " + entities.first);
				assert(false && "Could not find data store group");
			}
		}

		m_removeEntities.clear();
	}

}
